import sys
import pandas as pd
import numpy as np
import time
from PyQt6.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget, QProgressBar, QPushButton
from PyQt6.QtCore import pyqtSignal, QThread
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split

class CompositionPredictor:
    def __init__(self, excel_path, performance_columns, composition_columns, performance_str, max_iterations=20, tolerance=0.1):
        self.excel_path = excel_path  # excel路径
        self.performance_columns = performance_columns  # 属性列
        self.composition_columns = composition_columns  # 目标列
        self.performance_str = performance_str  # 输入性能值
        self.max_iterations = max_iterations  # 迭代次数
        self.tolerance = tolerance  # 允许误差
        self.data = self.load_data()

    def load_data(self):
        try:
            data = pd.read_excel(self.excel_path)
            print("数据读取成功")
            return data
        except Exception as e:
            print(f"读取数据时发生错误: {e}")
            exit()

    def train_random_forest(self, X, y):
        model = RandomForestRegressor(n_estimators=300, oob_score=True, min_samples_leaf=1)
        model.fit(X, y)
        return model

    def predict_composition(self, input_performance):
        # P-C 模型训练
        X_pc = self.data[self.performance_columns]
        y_pc = self.data[self.composition_columns]
        pc_model = self.train_random_forest(X_pc, y_pc)
        predicted_composition = pc_model.predict(input_performance)
        predicted_composition_df = pd.DataFrame(predicted_composition, columns=self.composition_columns)

        # C-P 模型预测性能
        predicted_performance = []
        performance_differences = []
        for i, performance in enumerate(self.performance_columns):
            y_cp = self.data[[performance]].values.ravel()
            cp_model = self.train_random_forest(self.data[self.composition_columns], y_cp)
            predicted_value = cp_model.predict(predicted_composition_df)
            predicted_performance.append(predicted_value[0])

            actual_value = input_performance.iloc[0, i]
            difference = abs((actual_value - predicted_value[0]) / actual_value)
            performance_differences.append(difference)

        return {
            "predicted_composition": [round(comp, 2) for comp in predicted_composition[0].tolist()],
            "predicted_performance": [round(perf, 2) for perf in predicted_performance],
            "performance_differences": [round(diff, 2) for diff in performance_differences]
        }


class CompositionPredictorThread(QThread):
    all_task_progress = pyqtSignal(int)
    sub_task_progress = pyqtSignal(int)
    results_ready = pyqtSignal(list, float)  # 新增一个信号，用于传递结果
    update_label = pyqtSignal(int, int, int)

    def __init__(self, excel_path, performance_columns, composition_columns, performance_str, max_iterations=20, tolerance=0.1):
        super().__init__()
        self.predictor = CompositionPredictor(excel_path, performance_columns,composition_columns,  performance_str, max_iterations, tolerance)
        self.stop_requested = False  # 初始化停止标志为 False

    def run(self):
        performance_values = list(map(float, self.predictor.performance_str.split(',')))
        input_performance = pd.DataFrame([performance_values], columns=self.predictor.performance_columns)
        total_iterations = self.predictor.max_iterations
        print("total_iterations", total_iterations)
        results = []  # 用于存储所有的结果
        count_within_tolerance = 0  # 初始设置一个0

        for iteration in range(total_iterations):
            if self.stop_requested:  # 检查是否请求停止
                print("检测到停止请求，提前退出训练循环")
                break

            start_time = time.time()
            # 只调用一次预测方法
            iteration_result = self.predictor.predict_composition(input_performance)
            results.append(iteration_result)  # 将每次迭代的结果加入到 results 中

            # 检查当前迭代中是否所有性能差异都在误差范围内
            if all(diff < self.predictor.tolerance for diff in iteration_result["performance_differences"]):
                count_within_tolerance += 1

            self.update_label.emit(iteration + 1, total_iterations, count_within_tolerance)

            # 更新总任务进度，计算百分比
            progress_percentage = int(((iteration + 1) / total_iterations) * 100)
            self.all_task_progress.emit(progress_percentage)  # 发射更新后的百分比

            # 模拟子任务进度
            elapsed_time = time.time() - start_time
            progress = 0
            update_interval = 0.05

            while progress < 100:
                time.sleep(update_interval)
                progress += int((update_interval / elapsed_time) * 100)
                self.sub_task_progress.emit(min(progress, 100))

            # 检查是否为最后一次迭代，避免最后一轮重置进度条
            if iteration < total_iterations - 1:
                self.sub_task_progress.emit(0)
        # print(results)
        # 打印结果，确保只输出 max_iterations 次
        for idx, result in enumerate(results):
            print(f"第{idx + 1}轮预测结果: {result}")

        # 发送结果信号
        self.results_ready.emit(results, self.predictor.tolerance)
